"""
用户认证相关的序列化器

这个文件定义了API数据序列化和反序列化的规则，
包括用户注册、登录、用户信息等的数据验证和转换。
"""
from rest_framework import serializers
from django.contrib.auth import authenticate
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from .models import User, UserProfile, LoginLog
import re


class UserRegistrationSerializer(serializers.ModelSerializer):
    """
    用户注册序列化器
    
    处理用户注册时的数据验证，包括用户名、邮箱、手机号、密码等字段的验证。
    确保数据的完整性和安全性。
    """
    
    # 密码字段（只写入，不返回）
    password = serializers.CharField(
        write_only=True,
        min_length=8,
        max_length=128,
        style={'input_type': 'password'},
        help_text='密码长度至少8位，包含字母和数字'
    )
    
    # 确认密码字段
    password_confirm = serializers.CharField(
        write_only=True,
        style={'input_type': 'password'},
        help_text='请再次输入密码进行确认'
    )
    
    class Meta:
        model = User
        fields = [
            'username', 'email', 'phone', 'password', 'password_confirm',
            'first_name', 'last_name', 'nickname'
        ]
        extra_kwargs = {
            'username': {
                'help_text': '用户名，3-30个字符，只能包含字母、数字和下划线'
            },
            'email': {
                'help_text': '邮箱地址，用于登录和接收通知'
            },
            'phone': {
                'help_text': '手机号码，11位数字'
            },
        }
    
    def validate_username(self, value):
        """
        验证用户名
        
        用户名规则：
        - 3-30个字符
        - 只能包含字母、数字、下划线
        - 不能以数字开头
        - 不能是保留关键字
        """
        if len(value) < 3:
            raise serializers.ValidationError('用户名至少需要3个字符')
        
        if len(value) > 30:
            raise serializers.ValidationError('用户名不能超过30个字符')
        
        if not re.match(r'^[a-zA-Z][a-zA-Z0-9_]*$', value):
            raise serializers.ValidationError('用户名只能包含字母、数字和下划线，且必须以字母开头')
        
        # 检查保留关键字
        reserved_names = ['admin', 'root', 'api', 'www', 'mail', 'ftp', 'test']
        if value.lower() in reserved_names:
            raise serializers.ValidationError('该用户名为系统保留，请选择其他用户名')
        
        return value
    
    def validate_email(self, value):
        """
        验证邮箱地址
        
        检查邮箱格式和唯一性
        """
        if User.objects.filter(email=value).exists():
            raise serializers.ValidationError('该邮箱已被注册')
        return value
    
    def validate_phone(self, value):
        """
        验证手机号码
        
        检查手机号格式和唯一性
        """
        if not re.match(r'^1[3-9]\d{9}$', value):
            raise serializers.ValidationError('请输入有效的手机号码')
        
        if User.objects.filter(phone=value).exists():
            raise serializers.ValidationError('该手机号已被注册')
        
        return value
    
    def validate_password(self, value):
        """
        验证密码强度
        
        使用Django内置的密码验证器
        """
        try:
            validate_password(value)
        except ValidationError as e:
            raise serializers.ValidationError(list(e.messages))
        return value
    
    def validate(self, attrs):
        """
        验证整体数据
        
        检查密码确认是否一致
        """
        if attrs['password'] != attrs['password_confirm']:
            raise serializers.ValidationError({
                'password_confirm': '两次输入的密码不一致'
            })
        
        # 移除确认密码字段，不需要保存到数据库
        attrs.pop('password_confirm')
        return attrs
    
    def create(self, validated_data):
        """
        创建用户
        
        使用验证后的数据创建新用户，并自动创建用户资料
        """
        # 提取密码
        password = validated_data.pop('password')
        
        # 创建用户
        user = User.objects.create_user(
            password=password,
            **validated_data
        )
        
        # 创建用户资料
        UserProfile.objects.create(user=user)
        
        return user


class UserLoginSerializer(serializers.Serializer):
    """
    用户登录序列化器
    
    处理用户登录验证，支持用户名、邮箱、手机号多种方式登录。
    """
    
    # 登录标识（用户名、邮箱或手机号）
    login_id = serializers.CharField(
        max_length=150,
        help_text='用户名、邮箱或手机号'
    )
    
    # 密码
    password = serializers.CharField(
        style={'input_type': 'password'},
        help_text='用户密码'
    )
    
    # 记住登录状态
    remember_me = serializers.BooleanField(
        default=False,
        help_text='是否记住登录状态'
    )
    
    def validate(self, attrs):
        """
        验证登录信息
        
        支持多种登录方式：用户名、邮箱、手机号
        """
        login_id = attrs.get('login_id')
        password = attrs.get('password')
        
        if not login_id or not password:
            raise serializers.ValidationError('请输入登录信息和密码')
        
        # 尝试不同的登录方式
        user = None
        
        # 1. 尝试用户名登录
        user = authenticate(username=login_id, password=password)
        
        # 2. 如果用户名登录失败，尝试邮箱登录
        if not user and '@' in login_id:
            try:
                user_obj = User.objects.get(email=login_id)
                user = authenticate(username=user_obj.username, password=password)
            except User.DoesNotExist:
                pass
        
        # 3. 如果邮箱登录失败，尝试手机号登录
        if not user and login_id.isdigit() and len(login_id) == 11:
            try:
                user_obj = User.objects.get(phone=login_id)
                user = authenticate(username=user_obj.username, password=password)
            except User.DoesNotExist:
                pass
        
        if not user:
            raise serializers.ValidationError('登录信息或密码错误')
        
        if not user.is_active:
            raise serializers.ValidationError('账户已被禁用')
        
        attrs['user'] = user
        return attrs


class UserSerializer(serializers.ModelSerializer):
    """
    用户信息序列化器
    
    用于返回用户基本信息，不包含敏感数据如密码。
    """
    
    # 显示名称（计算字段）
    display_name = serializers.CharField(source='get_display_name', read_only=True)
    
    # 全名（计算字段）
    full_name = serializers.CharField(source='get_full_name', read_only=True)
    
    # 头像URL
    avatar_url = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = [
            'id', 'username', 'email', 'phone', 'first_name', 'last_name',
            'nickname', 'bio', 'avatar', 'avatar_url', 'display_name', 'full_name',
            'email_verified', 'phone_verified', 'is_active', 'date_joined',
            'last_login', 'created_at', 'updated_at'
        ]
        read_only_fields = [
            'id', 'email_verified', 'phone_verified', 'is_active',
            'date_joined', 'last_login', 'created_at', 'updated_at'
        ]
    
    def get_avatar_url(self, obj):
        """
        获取头像URL
        
        如果用户有头像，返回完整URL；否则返回默认头像
        """
        if obj.avatar:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.avatar.url)
            return obj.avatar.url
        return None


class UserProfileSerializer(serializers.ModelSerializer):
    """
    用户资料序列化器
    
    用于用户资料的查看和更新
    """
    
    # 关联用户信息
    user = UserSerializer(read_only=True)
    
    class Meta:
        model = UserProfile
        fields = [
            'user', 'theme', 'language', 'timezone',
            'email_notifications', 'sms_notifications',
            'login_count', 'created_at', 'updated_at'
        ]
        read_only_fields = ['user', 'login_count', 'created_at', 'updated_at']


class PasswordChangeSerializer(serializers.Serializer):
    """
    密码修改序列化器
    
    用于用户修改密码时的数据验证
    """
    
    # 当前密码
    old_password = serializers.CharField(
        style={'input_type': 'password'},
        help_text='当前密码'
    )
    
    # 新密码
    new_password = serializers.CharField(
        min_length=8,
        style={'input_type': 'password'},
        help_text='新密码，至少8位字符'
    )
    
    # 确认新密码
    new_password_confirm = serializers.CharField(
        style={'input_type': 'password'},
        help_text='确认新密码'
    )
    
    def validate_old_password(self, value):
        """
        验证当前密码
        """
        user = self.context['request'].user
        if not user.check_password(value):
            raise serializers.ValidationError('当前密码错误')
        return value
    
    def validate_new_password(self, value):
        """
        验证新密码强度
        """
        try:
            validate_password(value)
        except ValidationError as e:
            raise serializers.ValidationError(list(e.messages))
        return value
    
    def validate(self, attrs):
        """
        验证密码确认
        """
        if attrs['new_password'] != attrs['new_password_confirm']:
            raise serializers.ValidationError({
                'new_password_confirm': '两次输入的新密码不一致'
            })
        
        if attrs['old_password'] == attrs['new_password']:
            raise serializers.ValidationError({
                'new_password': '新密码不能与当前密码相同'
            })
        
        return attrs


class LoginLogSerializer(serializers.ModelSerializer):
    """
    登录日志序列化器
    
    用于显示用户的登录历史记录
    """
    
    # 用户信息
    user_info = serializers.SerializerMethodField()
    
    # 会话时长（格式化）
    duration_display = serializers.SerializerMethodField()
    
    class Meta:
        model = LoginLog
        fields = [
            'id', 'user_info', 'ip_address', 'user_agent', 'status',
            'failure_reason', 'login_time', 'logout_time',
            'session_duration', 'duration_display'
        ]
        read_only_fields = ['id', 'login_time']
    
    def get_user_info(self, obj):
        """
        获取用户基本信息
        """
        return {
            'id': str(obj.user.id),
            'username': obj.user.username,
            'display_name': obj.user.get_display_name()
        }
    
    def get_duration_display(self, obj):
        """
        格式化会话时长显示
        """
        if obj.session_duration:
            hours = obj.session_duration // 3600
            minutes = (obj.session_duration % 3600) // 60
            seconds = obj.session_duration % 60
            
            if hours > 0:
                return f"{hours}小时{minutes}分钟{seconds}秒"
            elif minutes > 0:
                return f"{minutes}分钟{seconds}秒"
            else:
                return f"{seconds}秒"
        return None